home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 43 / Mac Magazin and MacEasy Magazine CD - Issue 43.iso / Software / Mobiles Büro / Newton / Newton Entwickler / DIL 2.0 Sample Code ƒ / SoupDrink-Mac-4 / Engine.c < prev    next >
C/C++ Source or Header  |  1997-04-17  |  23KB  |  646 lines

  1. /*
  2.  * Engine.c                                                      
  3.  *
  4.  *    Written by:    Rob Langhorne, J. Christopher Bell, and David Fedor
  5.  * 
  6.  *    Copyright:    © 1995-1997 by Apple Computer, Inc.  All rights reserved.
  7.  *
  8.  * This file is used both by the MacOS and Windows versions of SoupDrink; it contains
  9.  * nearly all the calls to the CDIL and FDIL code other than the initialization routines.
  10.  *
  11.  * SoupDrink() is the routine for soup drinking: uploading a soup to the desktop.
  12.  * UploadNewName() sends a frame holding a "name card" to the Newton.
  13.  * PrintEntry() and PrintTree() pretty-print the contents of a frame to a file.
  14.  * 
  15.  * Purpose:
  16.  *   To demonstrate the basic parts of FDILs and CDILs. The basic engines currently in
  17.  *   this code are the "soup drink" engine which uploads a Newton soup and the the
  18.  *   "new name" engine which downloads a business card to the Newton names database.
  19.  *
  20.  *   The soup drinking is split into two sections to illustrate both synchronous and
  21.  *   asynchronous reading. The first entry read is done asynchronously from this
  22.  *   function, with the callback function SoupDrinkCallback (below) doing the rest of
  23.  *   the communication synchronously.
  24.  * 
  25.  *   The protocol for the soup drink is:
  26.  *      Newton                                                             Desktop
  27.  *      ======                                                             =======
  28.  *                                                                    <---- "DRNK"
  29.  *     "DRNK" -->
  30.  *     "ENTR"-->
  31.  *     a frame (or a string if in spit mode)--->
  32.  *                                                                    <---- "OK"
  33.  *     [then repeat with ENTR command, or ...]
  34.  *     "END "--> 
  35.  *   
  36.  *  NOTE: The Newton "SPIT" command is supported for compatibility with older versions of this
  37.  *  sample. If the SPIT command was sent instead of DRNK, a text version of the entry
  38.  *  (NOT a frame) was sent. This was relevant only to a bug in some versions of Newton 1.x.    
  39.  */
  40.  
  41. #ifndef _windows
  42. #define forMac        // Codewarrior doesn't have a handy way to do this.
  43. #endif
  44.  
  45.  
  46. #include <string.h>
  47. #include <stdio.h>
  48.  
  49.  
  50. #ifdef forMac    // ****** stuff for MAC-OS applications ******
  51. #include <Types.h>
  52. #include <memory.h>
  53. #include "DILCPIPE.h" 
  54. #include "HLFDIL.h"
  55. #include "SoupDrink.h"
  56. #define Timeout 600        // this is currently in ticks but should be in milliseconds
  57. #define LongSwap 0        // don't need to swap longs on MacOS
  58.  
  59. #else           // ****** stuff for Windows applications *********
  60. #include <windows.h>
  61. #include "DILCPIPE.H" 
  62. #include "HLFDIL.h"
  63. #include "SOUPDRNK.H"
  64. #define Timeout 20000    // time out in 20 seconds
  65. typedef unsigned char   Str255[256];
  66. #define LongSwap 4        // when reading a long with CDPipeRead, need to swap bytes.
  67.  
  68. // Below two lines are only needed in 1.0 Windows DILs...
  69. #define CurrentTimeInSeconds() ((long)(GetTickCount() / 1000))
  70. #define  kTimeoutInSecs 15
  71.  
  72. #endif
  73.  
  74.  
  75.  
  76. #include "Engine.h"
  77. #define Encoding 0
  78. #define Swapping 0
  79.  
  80. extern CDILPipe        *ourPipe;
  81. extern void            *gThisObject;        // This is the only DIL frame active at one time in this app
  82. extern int            gInputMode;            // drink mode (receive frames) or spit mode (receive strings)
  83. extern char            gReceivedString[];         // received string; used in 'spit mode'
  84. extern long            gReceivedStringLen;        // received string length (see above)
  85. extern char         gTempBuffer [256];        // a global string buffer for input dialogs, etc
  86.  
  87.  
  88. // ieee reals have bytes in the opposite order on Windows versus Newton devices.
  89. // This function will swap the bytes to convert between one way and the other.
  90. // It can be used both when sending and when receiving doubles, since it is 
  91. // symmetric, and it won't do anything except on Windows, to make code cleaner.
  92.  
  93. double FlipDoubleIfNecessary(double theDouble)
  94. {
  95. #ifndef _windows
  96.     return theDouble;    // no flipping is necessary except on Windows
  97. #else
  98.     unsigned long tmpWord1;
  99.     unsigned long tmpWord2;
  100.     double tmpDouble;
  101.  
  102.     tmpWord1 = ((unsigned long *)&theDouble)[0];
  103.     tmpWord2 = ((unsigned long *)&theDouble)[1];
  104.     tmpWord1 =  ((tmpWord1 & 0x000000ff) << 24) |
  105.                 ((tmpWord1 & 0x0000ff00) <<  8) |
  106.                 ((tmpWord1 & 0x00ff0000) >>  8) |
  107.                 ((tmpWord1 & 0xff000000) >> 24);
  108.     tmpWord2 =  ((tmpWord2 & 0x000000ff) << 24) |
  109.                 ((tmpWord2 & 0x0000ff00) <<  8) |
  110.                 ((tmpWord2 & 0x00ff0000) >>  8) |
  111.                 ((tmpWord2 & 0xff000000) >> 24);
  112.     ((unsigned long *)&tmpDouble)[0] = tmpWord2;
  113.     ((unsigned long *)&tmpDouble)[1] = tmpWord1;
  114.     
  115.     return tmpDouble;
  116. #endif
  117. }
  118.  
  119.  
  120. CommErr SoupDrink() 
  121. {
  122.     char         soupName[255];
  123.     char         response[5];
  124.     long        length;
  125.     objErr        fErr = 0;
  126.     long        longLen;
  127.     Boolean        eom;
  128.     long        endTime;
  129.  
  130.     inputDialog((char *)soupName, "Names", "Enter Soup Name:");
  131.     if ('\0' == *soupName)        /*    Probably a cancel    */
  132.         return 0;
  133.     
  134.     if (strlen(soupName) > 253)
  135.         soupName[253] = 0;
  136.     strcat((char *)soupName, "\4");
  137.     
  138.     fErr = (short) InitializePipe();
  139.     if (fErr)
  140.         return fErr;        // don't need to dispose pipe if error
  141.  
  142.     // make the connection!
  143.     CHECKDILERROR((short) CDPipeListen(ourPipe, kDefaultTimeout, 0, 0));
  144. #ifndef Workaround10WinDILsBug
  145.     CHECKDILERROR((short) CDPipeAccept(ourPipe));
  146. #else
  147.     // This code was needed for the 1.0 Windows DILs.  (Not for 1.0.2, or MacOS.)
  148.     // You need to loop a little bit for the connection state to be set to 
  149.     // kCDIL_ConnectPending.  It might not do that if there's nobody on the
  150.     // other side of the cable, though!
  151.  
  152.     // Loop until the Newton device connects
  153.     endTime = CurrentTimeInSeconds() + kTimeoutInSecs;    // time at which we should stop looping
  154.     while (CurrentTimeInSeconds() < endTime) {
  155.         if (CDGetPipeState(ourPipe) == kCDIL_ConnectPending) {
  156.             CHECKDILERROR((short) CDPipeAccept(ourPipe));
  157.             break;
  158.         } else
  159.             CDIdle(ourPipe);
  160.     }
  161.  
  162.     if (CurrentTimeInSeconds() >= endTime) {    // did we time out?
  163.         CDPipeDisconnect(ourPipe) ;
  164.         return kOurTimeoutError;
  165.     }
  166. #endif        
  167.  
  168.     /*    Initiate conversation; tell the Newton that we want to do a 'DRNK' */
  169.     length = 4;
  170.     CHECKDILERROR((short) CDPipeWrite(ourPipe, (void *)"DRNK", &length, true,Swapping,Encoding,Timeout,0,0));
  171.     
  172.     /* send the name of the soup we want to search */
  173.     length = strlen(soupName);
  174.     CHECKDILERROR((short) CDPipeWrite(ourPipe, (void *)soupName, &length, true,Swapping,Encoding,Timeout,0,0));
  175.     
  176.     /* get the Newton response. Possibilities are:
  177.      *   "DRNK"  -- no problem; about to begin
  178.      *   "SPIT"  -- DRNK not supported.   ADSP and outputframe is a problem on some systems -
  179.      *              that is, 1.x Newton devices without the December 1995 system update (xxx333).
  180.      *              The Newton will spit strings representing the names. In this case,
  181.      *              you might want to 'flatten' the frames yourself using the CDILs but not FDILS.
  182.      *              See notes at top of file for more info.
  183.      *   "NONE"  -- that soup is not available.
  184.      */
  185.     length = 4;
  186.     CHECKDILERROR((short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0));
  187.     response[4] = 0;
  188.     if (strcmp(response, "DRNK") == 0)
  189.         gInputMode = kDrinkMode;
  190.     else if (strcmp(response, "SPIT") == 0)
  191.         gInputMode = kSpitMode;
  192.     else if (strcmp(response, "NONE") == 0) {
  193.         PostAlertMessage("Could not open that soup on Newton.", "", "", "");
  194.         CDPipeDisconnect(ourPipe);
  195.         return(0);
  196.         }
  197.         
  198.     length = 4;
  199.     
  200.     /* receive a response; "END " for no more entries, "ENTR" for another soup entry */
  201.     CHECKDILERROR((short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0));
  202.     
  203.     response[4] = 0;                        /* make it a c string */
  204.     if (strcmp(response, "END ") == 0) {    /* if there are no more entries */
  205.         CDPipeDisconnect(ourPipe);
  206.         PostAlertMessage("There are no entries in this soup.", "", "", "");
  207.         return(0);
  208.         }
  209.     if (strcmp(response, "ENTR") != 0) {
  210.         PostAlertMessage("Received unknown command:", response, "", "");
  211.         CDPipeDisconnect(ourPipe);
  212.         return(0);
  213.         }
  214.  
  215.     //    read frame as unbound data
  216.     gThisObject = FDCreateObject(kDILFrame, nil);
  217.  
  218.     gReceivedStringLen = kMAXSTR;
  219.     longLen = 4;
  220.     if (gInputMode == kDrinkMode) {
  221.         fErr = (short) FDget(gThisObject, kDILFrame, ourPipe, Timeout, (CDILPipeCompletionProcPtr)SoupDrinkCallback, 0);
  222.     } else {
  223.         // we're in "spit" mode; the newton says it can't send frames.
  224.         fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedStringLen, &longLen, &eom,LongSwap,Encoding,Timeout,0,0);
  225.         if (fErr == 0)
  226.             fErr = (short) CDPipeRead(ourPipe, (void *) &gReceivedString[0], &gReceivedStringLen, &eom,
  227.                                         Swapping,Encoding,Timeout,(CDILPipeCompletionProcPtr)SoupDrinkCallback, 0);
  228.     }
  229.         
  230.     if (fErr) {
  231.         CDPipeDisconnect(ourPipe);
  232.         PostAlertMessage("Read returned:",ErrorStrings(fErr, gTempBuffer) ,"", "");
  233.         return 0;
  234.         }
  235.  
  236.     return fErr;    
  237. }
  238.  
  239.  
  240. /********************************************************************************
  241.  * SoupDrinkCallback
  242.  *
  243.  * SoupDrinkCallback is the drinking soup 'read' callback function
  244.  */
  245. /* for 16 bit Windows... void FAR _loadds  */
  246. #ifdef forWin16
  247. void FAR _loadds SoupDrinkCallback (CommErr errorValue, void *pData, Size Count, long refCon, long lFlags)
  248. #else
  249. static void      SoupDrinkCallback (CommErr errorValue, void *pData, Size Count, long refCon, long lFlags)
  250. #endif 
  251. {
  252.     FILE             *fp;        /* file reference */
  253.     slotDefinition *list = nil;
  254.     long            fErr = 0, len = 3;
  255.     long            longLen;
  256.     long            length;
  257.     char             response[255];
  258.     Boolean            eom;
  259.     short            x;
  260.  
  261.     if (errorValue)
  262.     {
  263.         PostAlertMessage("Error reading first frame:", ErrorStrings(errorValue, gTempBuffer), "", "");
  264.         FDDisposeObject(gThisObject);
  265.         CDPipeDisconnect(ourPipe);
  266.         return;
  267.     }
  268.     
  269.     /*    open file for entry (append)        */
  270.     fp = fopen("SoupData.out", "w+");
  271.     if (!fp)
  272.     {
  273.         PostAlertMessage("Could not open disk file for output.", "", "", "");
  274.         FDDisposeObject(gThisObject);
  275.         CDPipeDisconnect(ourPipe);
  276.         return;
  277.     }
  278.     
  279.     do {    /*    traverse frames        */
  280.         if (gInputMode == kSpitMode) /* we are just receiving strings, not frames */
  281.             {
  282.             gReceivedString[gReceivedStringLen] = 0;    /* turn it into c string */
  283.             fprintf(fp, gReceivedString);                /* send the string to the file */
  284.             fprintf(fp, "\n");                            /* send a carriage return char */
  285.             }
  286.         else {        
  287.             /*    We should have an unbound frame    list */
  288.             list = FDGetUnboundList(gThisObject);    
  289.             if (!list)                            /* if not, we got an empty soup frame?; fail! */
  290.                 break;
  291.                 
  292.             /*    traverse list        */
  293.             for (x= 0; x < list->peerCnt; x++)
  294.                 printTree(fp, &list[x], 1);
  295.     
  296.             fputc('\n', fp);
  297.             fputc('\n', fp);
  298.             fputc('\n', fp);
  299.     
  300.             FDFreeUnboundList(gThisObject, list);    
  301.             list = nil;
  302.         }
  303.             
  304.         if (fErr)
  305.             PostAlertMessage("Unbound List stuff returned an error:", ErrorStrings(fErr, gTempBuffer), "", "");
  306.         else {
  307.             /*    read next frame    */
  308.             len = 3;
  309.             fErr = CDPipeWrite(ourPipe, (void *)"OK\4", &len, true,Swapping,Encoding,Timeout,0,0) ; /* acknowledge receipt! */
  310.             if (!fErr) {
  311.                 length = 4;
  312.                 
  313.                 /* receive a response; "END " for no more entries, "ENTR" for another soup entry */
  314.                 fErr = (short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0);
  315.                 if (fErr) {
  316.                     PostAlertMessage("Read returned an error:",ErrorStrings(fErr, gTempBuffer) ,"", "");
  317.                     break;
  318.                 }
  319.                     
  320.                 response[4] = 0;                        /* make it a c string */
  321.                 if (strcmp(response, "END ") == 0)        /* if there are no more entries */
  322.                     break;
  323.                 if (strcmp(response, "ENTR") != 0) {
  324.                     PostAlertMessage("Received unknown command:", response, "", "");
  325.                     break;
  326.                 }
  327.  
  328.                 // there's another entry coming down; read it in and loop
  329.                 gReceivedStringLen = kMAXSTR;
  330.                 longLen = 4; 
  331.         
  332.                 if (gInputMode == kDrinkMode)
  333.                     fErr = FDget(gThisObject, kDILFrame, ourPipe, 500*60, 0, 0);
  334.                 else {
  335.                     fErr = CDPipeRead(ourPipe, (void *) &gReceivedStringLen, &longLen, &eom,Swapping,Encoding,Timeout,0,0);
  336.                     fErr = CDPipeRead(ourPipe, (void *) &gReceivedString[0], &gReceivedStringLen, &eom,Swapping,Encoding,Timeout,0,0);
  337.                 }
  338.             }
  339.         }        
  340.     } while (!fErr && gThisObject);
  341.     
  342.  
  343.     /* Clean up */
  344.     if (fErr)
  345.         PostAlertMessage("At end of soupdrink, got an error:", ErrorStrings(fErr, gTempBuffer), "", "");
  346.     
  347.     fflush(fp);        
  348.     fclose(fp);
  349.     if (list)
  350.         FDFreeUnboundList(gThisObject, list);
  351.     FDDisposeObject(gThisObject);
  352.     CDPipeDisconnect(ourPipe);
  353. }
  354.  
  355.  
  356.  
  357.  
  358. /*
  359.  * UploadNewName
  360.  *
  361.  * This function connects to a Newton and sends it a "name" for the names application.
  362.  */
  363. CommErr UploadNewName ()
  364. {
  365.     CommErr        fErr = 0;
  366.     void        *entry, *name;
  367.     void        *phones;
  368.     long        cardType = 4, len;
  369.     char        pClass[] = "person";
  370.     char        fName[] = "Howard";
  371.     char        lName[] = "Duck";
  372.     char        phoneNo[] = "555-1212";
  373.     char         addr[]    = "123 Sesame Street";
  374.     char        town[] = "Anytown";
  375.     char        state[] = "CA";
  376.     char        zip[] = "95014";
  377.     char        sName[] = "Duck";
  378.     char         response[5];
  379.     long        length;
  380.     Boolean        eom;
  381.     long        endTime;
  382.     double        mydouble;
  383.     
  384.     
  385.     fErr = (short) InitializePipe();
  386.     if (fErr)
  387.         return fErr;    // don't need to dispose pipe if error
  388.  
  389.     // make the connection!
  390.     CHECKDILERROR((short) CDPipeListen(ourPipe, kDefaultTimeout, 0, 0 ) );
  391. #ifndef _windows
  392.     CHECKDILERROR((short) CDPipeAccept(ourPipe));
  393. #else
  394.     // This code doesn't need to be done on the MacOS side, but is currently required
  395.     // for Windows.  You need to loop a little bit for the connection state to be
  396.     // set to kCDIL_ConnectPending.  It might not do that if there's nobody on the
  397.     // other side of the cable, though!
  398.  
  399.     // Loop until the Newton device connects
  400.     endTime = CurrentTimeInSeconds() + kTimeoutInSecs;    // time at which we should stop looping
  401.     while (CurrentTimeInSeconds() < endTime) {
  402.         if (CDGetPipeState(ourPipe) == kCDIL_ConnectPending) {
  403.             CHECKDILERROR((short) CDPipeAccept(ourPipe));
  404.             break;
  405.         } else
  406.             CDIdle(ourPipe);
  407.     }
  408.  
  409.     if (CurrentTimeInSeconds() >= endTime) {    // did we time out?
  410.         CDPipeDisconnect(ourPipe) ;
  411.         return kOurTimeoutError;
  412.     }
  413. #endif
  414.  
  415.     /*    Create an object        */
  416.  
  417.     // in the future, errors should delete name, phones, entry objects.
  418.     
  419.     name = FDCreateObject(kDILFrame, NULL);    
  420.     CHECKDILERROR((short) FDbindSlot(name, "Class", (void *)&pClass, kDILSymbol, strlen(pClass), -1, NULL));
  421.     CHECKDILERROR((short) FDbindSlot(name, "first", (void *)&fName, kDILString, strlen(fName), -1, NULL));
  422.     CHECKDILERROR((short) FDbindSlot(name, "last", (void *)&lName, kDILString, strlen(lName), -1, NULL));
  423.  
  424.     phones = FDCreateObject(kDILArray, NULL);
  425.     CHECKDILERROR((short) FDbindSlot(phones, "HomePhone", (void *)&phoneNo, kDILString, strlen(phoneNo), -1, NULL));
  426.  
  427.     entry = FDCreateObject(kDILFrame, NULL);
  428.     CHECKDILERROR((short) FDbindSlot(entry, "cardType", (void *)&cardType, kDILInteger, sizeof(cardType), -1, NULL)) ;
  429.     CHECKDILERROR((short) FDbindSlot(entry, "Name", (void *)name, kDILFrame, 0, -1, NULL));
  430.     CHECKDILERROR((short) FDbindSlot(entry, "Address", (void *)&addr, kDILString, strlen(addr), -1, NULL)) ;
  431.     CHECKDILERROR((short) FDbindSlot(entry, "City", (void *)&town, kDILString, strlen(town), -1, NULL)) ;
  432.     CHECKDILERROR((short) FDbindSlot(entry, "Region", (void *)&state, kDILString, strlen(state), -1, NULL)) ;
  433.     CHECKDILERROR((short) FDbindSlot(entry, "Postal_Code", (void *)&zip, kDILString, strlen(zip), -1, NULL)) ;
  434.     CHECKDILERROR((short) FDbindSlot(entry, "phones", (void *)phones, kDILArray, 0, -1, NULL)) ;                        
  435.     CHECKDILERROR((short) FDbindSlot(entry, "sorton", (void *)&sName, kDILString, strlen(sName), 0, "Name")) ;    
  436.  
  437.     // and just to show how it works, we add a slot which holds a real number.
  438.     mydouble = FlipDoubleIfNecessary(3.14159);        // ieee reals have bytes in the opposite order...
  439.     CHECKDILERROR((short) FDbindSlot(entry, "pi", (void *)&mydouble, kDILBinaryObject, 8, 8, "Real"));
  440.  
  441.     /*    Initiate conversation    */
  442.     len = 5;
  443.     CHECKDILERROR((short) CDPipeWrite (ourPipe, (void *)"NAME\4", &len, true, Swapping,Encoding,Timeout, 0, 0)) ;
  444.     
  445.     /*    Send a frame        */
  446.     CHECKDILERROR((short) FDput(entry, kDILFrame, ourPipe)) ;
  447.     
  448.     FDDisposeObject(phones);
  449.     FDDisposeObject(name);
  450.     FDDisposeObject(entry);
  451.     
  452.     // wait for the ack back from the Newton (or for 30 seconds) before we disconnect
  453.     length = 2;
  454.     CHECKDILERROR((short) CDPipeRead(ourPipe, (void *) response, &length, &eom,Swapping,Encoding,Timeout,0,0));
  455.  
  456.     CDPipeDisconnect(ourPipe) ;
  457.     
  458.     return fErr;    
  459.  
  460. }
  461.  
  462.  
  463. void    printEntry (FILE * fp, slotDefinition *thisEntry)
  464. {    
  465.     if (thisEntry->slotName)
  466.         fprintf( fp, "%s : ", thisEntry->slotName);
  467.     
  468.     switch (thisEntry->varType)
  469.     {
  470.         case kDILCharacter:            /*    ASCII Character                    */
  471.             fprintf( fp, "'%c'\n", *(char *)thisEntry->var);
  472.             break;
  473.             
  474.         case kDILUnicodeCharacter:    /*    Unicode Character                */
  475.             {
  476.                 char c = *(((char *)thisEntry->var)+1);
  477.                 fprintf( fp,  "$%c\n", (char *)c);
  478.             }
  479.             break;
  480.             
  481.         case kDILString:            /*    String (null-terminated)        */
  482.             if (thisEntry->oClass)
  483.                 // there's a special class defined for this string; show it.
  484.                 fprintf( fp, "\"%s\" (class '%s)\n", (char *)thisEntry->var, (char *)thisEntry->oClass);
  485.             else
  486.                 // generic string; no special class.
  487.                 fprintf( fp,  "\"%s\"\n", (char *)thisEntry->var);
  488.             break;
  489.             
  490.         case kDILBoolean:            /*    Boolean                            */
  491.             if (*(Boolean *)thisEntry->var)
  492.                 fprintf( fp,  "TRUE\n");
  493.             else
  494.                 fprintf( fp,  "FALSE\n");
  495.             break;
  496.             
  497.         case kDILImmediate:            /*    Indeterminate Immediate type    */
  498.         case kDILInteger:            /*    Integer (4 byte)                */
  499.             fprintf( fp, "#%ld\n", *(long *)thisEntry->var);
  500.             break;
  501.             
  502.         case kDILPlainArray:        /*    Anonymous Array                    */
  503.             fprintf (fp, "PLAINARRAY\n");
  504.             break;
  505.             
  506.         case kDILArray:                /*    Named Array                        */
  507.             if (thisEntry->oClass)
  508.                 fprintf (fp, "NAMEDARRAY (class '%s)\n", thisEntry->oClass);
  509.             else
  510.                 fprintf (fp, "NAMEDARRAY (No class???)\n");
  511.             break;
  512.         
  513.         case kDILFrame:                /*    Frame                            */
  514.             fprintf (fp, "FRAME \n");
  515.             break;
  516.         
  517.         case kDILSmallRect:            /*    Small rect                        */
  518.             fprintf (fp, "SMALLRECT\n");
  519.             break;
  520.         
  521.         case kDILPrecedent:            /*    Repeated Item                    */
  522.             fprintf (fp, "PRECEDENT %s\n", (char *)thisEntry->var);
  523.             break;
  524.         
  525.         case kDILSymbol:            /*    Object Symbol                    */
  526.             fprintf( fp,  "'%s\n", (char *)thisEntry->var);
  527.             break;
  528.         
  529.         case kDILBinaryObject:        /*    Small Binary Object ( < 32K )    */
  530.             if (thisEntry->oClass)
  531.                 if (0==strcmp(thisEntry->oClass,"Real")) {
  532.                     double tmpDouble;
  533.                     tmpDouble = FlipDoubleIfNecessary(*(double *)thisEntry->var);
  534.                     fprintf( fp,  "%f\n", tmpDouble);
  535.                 }
  536.                 else
  537.                     fprintf( fp,  "<%s, length %ld>\n", thisEntry->oClass, (ulong *) thisEntry->length);
  538.             else
  539.                 fprintf( fp,  "<binary, length %ld>\n", (ulong *) thisEntry->length);
  540.             break;
  541.         
  542.         case kDILNIL:                /*    nil object                        */
  543.             fprintf (fp, "NIL\n");
  544.             break;
  545.         
  546.         case kDILBLOB:                /*    Large Binary Object                */
  547.             fprintf (fp, "BLOB\n");
  548.             break;
  549.         
  550.         default:                    // ~~~~~ ignore these
  551.             fprintf (fp, "UNKNOWN TYPE\n");
  552.             break;
  553.     }
  554. }
  555.  
  556. //========================================================================================
  557. // printTree
  558.  
  559. // printTree pretty prints the output, traversing the simple "tree" of data
  560. //========================================================================================
  561. void printTree (FILE * fp, slotDefinition *thisEntry, short depth)
  562. {
  563.     short i;
  564.     short y;
  565.     
  566.     for (i = 0; i < depth; i++)
  567.         fputc('\t', fp);
  568.         
  569.     printEntry(fp, thisEntry);
  570.     
  571.     if (thisEntry->children)
  572.         for (y= 0; y < thisEntry->childCnt; y++)
  573.             printTree(fp, &(thisEntry->children[y]), depth + 1);
  574. }
  575.  
  576.  
  577. /* ErrorStrings
  578.  * 
  579.  * Purpose: return error string based on error number from the CDIL or FDIL
  580.  */
  581. char* ErrorStrings(CommErr theErr, char* theString)
  582. {
  583.     switch (theErr)
  584.         {
  585.         case kOurTimeoutError:  strcpy((char*) theString, 
  586.             (char*) "Timeout error. (Determined by SoupDrink)"); break;
  587.         case -97:  strcpy((char*) theString, 
  588.             (char*) "The port is busy. Quit the relevant application or restart if necessary (from ATalk Driver)");  break;
  589.  
  590.         // CDIL errors (see DILCPipe.h)
  591.         case -28701:  strcpy((char*) theString, 
  592.             (char*) "Error on memory allocation.");  break;
  593.         case -28702:  strcpy((char*) theString, 
  594.             (char*) "DIL pipe was set to a bad state.");  break;
  595.         case -28703:  strcpy((char*) theString, 
  596.             (char*) "An unknown exception has occurred.");  break;
  597.         case -28704:  strcpy((char*) theString, 
  598.             (char*) "The queue of asynchronous calls is full.");  break;
  599.         case -28705:  strcpy((char*) theString, 
  600.             (char*) "Pipe has not been initialized.");  break;
  601.         case -28706:  strcpy((char*) theString, 
  602.             (char*) "Parameter passed in was invalid.");  break;
  603.         case -28707:  strcpy((char*) theString, 
  604.             (char*) "Pipe is not ready for operation.");  break;
  605.         case -28708:  strcpy((char*) theString, 
  606.             (char*) "Timeout during DIL operation.");  break;
  607.  
  608.         // FDIL errors (see HLFDIL.h)
  609.         case -28801:  strcpy((char*) theString, 
  610.             (char*) "Out of heap memory");  break;
  611.         case -28802:  strcpy((char*) theString, 
  612.             (char*) "Out of temporary or other memory");  break;
  613.         case -28803:  strcpy((char*) theString, 
  614.             (char*) "Unknown slot");  break;
  615.         case -28804:  strcpy((char*) theString, 
  616.             (char*) "Slot size exceeded");  break;
  617.         case -28805:  strcpy((char*) theString, 
  618.             (char*) "Slot size is required");  break;
  619.         case -28806:  strcpy((char*) theString, 
  620.             (char*) "Unexpected data type");  break;
  621.  
  622.         // other errors
  623.         case -28003:  strcpy((char*) theString, 
  624.             (char*) "The communication operation was aborted.");  break;
  625.         case -28009:  strcpy((char*) theString, 
  626.             (char*) "Bad connection detected");  break;
  627.         case -28017:  strcpy((char*) theString, 
  628.             (char*) "Out of memory");  break;
  629.         case -28029:  strcpy((char*) theString, 
  630.             (char*) "Cannot connect to modem; no response.");  break;
  631.         case -28030:  strcpy((char*) theString, 
  632.             (char*) "Disconnection detected.");  break;
  633.         case -28100:  strcpy((char*) theString, 
  634.             (char*) "Disconnect occurred while reading.");  break;
  635.         case -28101:  strcpy((char*) theString, 
  636.             (char*) "An error occurred while reading.");  break;
  637.         case -28102:  strcpy((char*) theString, 
  638.             (char*) "The communication tool was not found");  break;
  639.         case -28103:  strcpy((char*) theString, 
  640.             (char*) "Bad modem tool version");  break;
  641.         default: sprintf(theString, "%ld", theErr);
  642.         }
  643.     return (char*) theString;
  644. }
  645.  
  646.